// ArchiveExtractCallback.h

#ifndef __ARCHIVE_EXTRACT_CALLBACK_H
#define __ARCHIVE_EXTRACT_CALLBACK_H

#include "Common/FileSystem/Wildcard.h"

#include "Common/COM/IPassword.h"

#include "Common/Stream/FileStreams.h"
#include "Common/Stream/ProgressUtils.h"

#include "Common/Archive/IArchive.h"

#include "Common/Archive/OutStreamWithCRC.h"

#include "Common/Archive/ExtractMode.h"
#include "IFileExtractCallback.h"
#include "OpenArchive.h"

namespace Common
{
namespace Archive
{

class ATL_NO_VTABLE CArchiveExtractCallback :
	public CComObjectRootEx<CComSingleThreadModel>,
  public IArchiveExtractCallback,
  // public IArchiveVolumeExtractCallback,
  public ICryptoGetTextPassword,
  public ICompressProgressInfo 
{
  const Archive::CArc *_arc;
  const Common::FileSystem::Wildcard::CCensorNode *_wildcardCensor;
  CComPtr<IFolderArchiveExtractCallback> _extractCallback2;
  CComPtr<ICompressProgressInfo> _compressProgress;
  CComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword;
  CString _directoryPath;
  Common::Archive::Extract::PathMode _pathMode;
  Common::Archive::Extract::OverwriteMode _overwriteMode;

  CString _diskFilePath;
  CString _filePath;
  UINT64 _position;
  bool _isSplit;

  bool _extractMode;

  bool WriteCTime;
  bool WriteATime;
  bool WriteMTime;

  bool _encrypted;

  struct CProcessedFileInfo
  {
    FILETIME CTime;
    FILETIME ATime;
    FILETIME MTime;
    UINT32 Attrib;
  
    bool CTimeDefined;
    bool ATimeDefined;
    bool MTimeDefined;
    bool AttribDefined;

    bool IsDir;
  } _fi;

  UINT32 _index;
  UINT64 _curSize;
  bool _curSizeDefined;
  COutFileStream *_outFileStreamSpec;
  CComPtr<ISequentialOutStream> _outFileStream;

  COutStreamWithCRC *_crcStreamSpec;
  CComPtr<ISequentialOutStream> _crcStream;

  CStringVector _removePathParts;

  bool _stdOutMode;
  bool _testMode;
  bool _crcMode;
  bool _multiArchives;

  CComPtr<ICompressProgressInfo> _localProgress;
  UINT64 _packTotal;
  UINT64 _unpTotal;

  void CreateComplexDirectory(const CStringVector &dirPathParts, CString &fullPath);
  HRESULT GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined);
  HRESULT GetUnpackSize();

  //helper fuctions for GetStream function
  HRESULT GetFileProperties(int index);
  HRESULT GetArcFileProperties(int index);

public:

  CComObject<CLocalProgress> *LocalProgressSpec;

  UINT64 NumFolders;
  UINT64 NumFiles;
  UINT64 UnpackSize;
  UINT32 CrcSum;
  
	BEGIN_COM_MAP(CArchiveExtractCallback)
		COM_INTERFACE_ENTRY(IArchiveExtractCallback)
		COM_INTERFACE_ENTRY(ICryptoGetTextPassword)
		COM_INTERFACE_ENTRY(ICompressProgressInfo)
	END_COM_MAP()


	DECLARE_PROTECT_FINAL_CONSTRUCT()

	HRESULT FinalConstruct()
	{
		WriteCTime = true;
		WriteATime = true;
		WriteMTime = true;
		_multiArchives = false;
  
		LocalProgressSpec = new CComObject<CLocalProgress>();
		LocalProgressSpec->FinalConstruct();
		_localProgress = LocalProgressSpec;
		return S_OK;
	}

	void FinalRelease()
	{
	}

  // COM_INTERFACE_ENTRY(IArchiveVolumeExtractCallback)

  /* INTERFACE IProgress */ 
  STDMETHOD(SetTotal)(UINT64 total); 
  STDMETHOD(SetCompleted)(const UINT64 *completeValue) ; 
  
  //INTERFACE IArchiveExtractCallback
  STDMETHOD(GetStream)(UINT32 index, ISequentialOutStream **outStream,  INT32 askExtractMode) ; 
  STDMETHOD(PrepareOperation)(INT32 askExtractMode) ; 
  STDMETHOD(SetOperationResult)(INT32 resultEOperationResult) ; 
  

  STDMETHOD(SetRatioInfo)(const UINT64 *inSize, const UINT64 *outSize);

  // IArchiveVolumeExtractCallback
  // STDMETHOD(GetInStream)(const wchar_t *name, ISequentialInStream **inStream);

  STDMETHOD(CryptoGetTextPassword)(BSTR *password);

  /*CArchiveExtractCallback():
      WriteCTime(true),
      WriteATime(true),
      WriteMTime(true),
      _multiArchives(false)
  {
    LocalProgressSpec = new CLocalProgress();
    _localProgress = LocalProgressSpec;
  }*/

  void InitForMulti(bool multiArchives,
      Extract::PathMode pathMode,
      Extract::OverwriteMode overwriteMode)
  {
    _multiArchives = multiArchives;
    _pathMode = pathMode;
    _overwriteMode = overwriteMode;
    NumFolders = NumFiles = UnpackSize = 0;
    CrcSum = 0;
  }

  void Init(
      const Common::FileSystem::Wildcard::CCensorNode *wildcardCensor,
      const CArc *arc,
      IFolderArchiveExtractCallback *extractCallback2,
      bool stdOutMode, bool testMode, bool crcMode,
      const CString &directoryPath,
      const CStringVector &removePathParts,
      UINT64 packSize);

};

}
}

#endif
